from django.shortcuts import get_object_or_404, render_to_response
from django.http import HttpResponseRedirect, HttpResponse, Http404
from django.core.urlresolvers import reverse
from django.template import RequestContext
from interview.models import Question, QuestionSet, QuestionSetList, Rule, Explanation
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User

def LogUserIn(request):
    if request.method == 'POST':
        username = request.POST["username"]
        password = request.POST["password"]
        user = authenticate(username=username, password=password)
        if user is not None:
            if user.is_active:
                login(request, user)
                # success                
                #here you should set questions sets list to the user, depending on the role, etc.
                state="Welcome!!!"
                return render_to_response('interview/index.html', {'greetings':state}, context_instance = RequestContext(request))
            else:
              # disabled account
                state = "Your Account is Inactive!!! Please Contact an Administrator"
                return render_to_response('interview/index.html', {'greetings' : state}, context_instance = RequestContext(request))
            
        else:
          # invalid login
            state = "Login Failed... Try Again."
        return render_to_response('interview/index.html', {'greetings':state}, context_instance = RequestContext(request))
      
def LogUserOut(request):
    logout(request)
    state = "You have successfully logged out!"    
    return render_to_response('interview/index.html', {'greetings' : state}, context_instance = RequestContext(request))

def checkUser(username):
	try:
		user = User.objects.get(username=username)
	except User.DoesNotExist :
		return False
	return True


def register(request):
    if request.method == 'POST':
        username = request.POST["username"]
        password = request.POST["password"]
	confirmp = request.POST["confirmPassword"]
        #email = request.POST["email"]
        #user = User.objects.create_user(username=username, email = email, password = password)
        if checkUser(username) :
            state="Username in use! Please try another"
            return render_to_response('interview/register.html', {'state':state}, context_instance=RequestContext(request))    

        if len(username) < 1 :
            state="Username must have more than 1 character"
            return render_to_response('interview/register.html', {'state':state}, context_instance=RequestContext(request))
        if len(password) < 1 :
            state="Password must have more than 1 character"
            return render_to_response('interview/register.html', {'state':state}, context_instance=RequestContext(request))            
        if password == confirmp :         
            user = User.objects.create_user(username=username, email = "not@used.now", password = password)
            user.save()
            user = authenticate(username=username, password=password)
            login(request, user)
            greetings = "Hello there! You can use my system if you want!"
            return render_to_response('interview/index.html', {'greetings':greetings}, context_instance=RequestContext(request))
        else: 
            state= "Passwords do not match! Please Try Again"
            return render_to_response('interview/register.html', {"state":state}, context_instance=RequestContext(request))

        user = User.objects.create_user(username=username, email = "not@used.now", password = password)
        user.save()
        user = authenticate(username=username, password=password)
        login(request, user)
        greetings = "Hello there! You can use my system if you want!"
        return render_to_response('interview/index.html', {'greetings':greetings}, context_instance=RequestContext(request))
        #return index(request)
    else:
        return render_to_response('interview/register.html', {}, context_instance=RequestContext(request))

#@login_required()
def index(request):
    greetings = "Hello there! You can use my system if you want!"
    return render_to_response('interview/index.html', {'greetings':greetings}, 
                                  context_instance=RequestContext(request))

#normal questions view.
def questions(request):
    
    #when users login, they should get list of questions sets in their session.
    #if they don't have list, let them try a few questions as an anonymous user.
    
    if not('counter' in request.session):
        request.session['counter'] = 1
        request.session['facts'] = ['always']
        request.session['recommendations'] = []
        request.session['reasonings_to_display'] = ["You always get this."]
        
        #currently only for a test.
        question_set_list = QuestionSetList.objects.get(pk=1)
        request.session['my_questions'] = buildListOfAllQuestions(question_set_list)
        #not used yet
#        #request.session['my_questions'] = updateMyQuestions(request.session['facts'], buildListOfAllQuestions(question_set_list))
        
        
        
#    elif(request.session['counter'] > 4 and request.user.is_anonymous()):
#        return render_to_response('registration/login.html', {},
#                                  context_instance=RequestContext(request))
    #only for now for debugging.
    elif(request.session['counter'] > len(request.session['my_questions'])):
        request.session['counter'] = 1
        request.session['facts'] = ['always']
        request.session['recommendations'] = []
        request.session['reasonings_to_display'] = ["You always get this."]
        
        #currently for only a test.
        question_set_list = QuestionSetList.objects.get(pk=1)
        request.session['my_questions'] = buildListOfAllQuestions(question_set_list)
        
        #not used yet
#        request.session['my_questions'] = updateMyQuestions(request.session['facts'], buildListOfAllQuestions(question_set_list))
        
    else:
        request.session['counter'] += 1

###############################################################################################
#        Simple Array out of bounds check, just to work on website easier, rob
###############################################################################################    
    if(not request.session['counter'] > len(request.session['my_questions'])) : 
        
        ######## modified by Hideo for feature 5. ###########
        q = request.session['my_questions'][request.session['counter']-1]
        skip_counter = 0
        while(str(q.fact) in request.session['facts'] or "not_"+str(q.fact) in request.session['facts']):
            skip_counter += 1
            request.session['counter'] += 1
            if(request.session['counter'] >= len(request.session['my_questions'])):
                if(request.session['counter'] > len(request.session['my_questions'])):
                    request.session['counter'] -= 1
                break
            q = request.session['my_questions'][request.session['counter']-1]
        
        if(skip_counter == 1):
            return genPage(request)
        ##################### feature 5. #####################
        return render_to_response('interview/questions.html', {'question':q,
                                                           'counter':request.session['counter'],
                                                           #'debug_info':request.session['my_questions'],
                                                           'user':request.user},
                                                           context_instance=RequestContext(request))

    else: 
        state="You have completed all of the questions!!"
        return render_to_response('interview/index.html', {'greetings' : state},
                                                           context_instance=RequestContext(request))

#this function is to get a list of sets of questions in django format and return python list of all questions to be asked in order.
def buildListOfAllQuestions(question_set_list):
    questions_list = []
    for question_set in question_set_list.question_sets_list.all():
        if(len(list(question_set.question_sets_for_question_sets.all()))>0):
            for question_sets_for_question_sets in question_set.question_sets_for_question_sets.all():
                for question in question_sets_for_question_sets.question_sets_for_questions.all():
                    questions_list.append(question)
        else:
            for question in question_set.question_sets_for_questions.all():
                questions_list.append(question)
    
    return questions_list


#this function is to update myQuestions in session. depending on answered questions and obtained facts in session, "when" condition for
#questions should be examined and eliminate questions that will not be asked.
#currently not used yet.
#def updateMyQuestions(facts, questions_list):                                   #this should not be string
#    result_list = [question for question in questions_list if(tryWhenCondition("question.when", facts))]
#
#    return result_list
#    
##this function is only called from a function above.(updateMyQuestions)
#def tryWhenCondition(when, facts):
#    when_code = "if(" + when
#    if_when = False
#    
#    #clean up extra spaces.
#    while(when_code.find("  ") >= 0):
#        when_code = when_code.replace("  ", " ")
#    
#    #add "in facks" before all ands or ors.
#    when_code = when_code.replace(" and ", " in facts and ")
#    when_code = when_code.replace(" or ", " in facts or ")
#        
#    #add "in facts" after the last fact.
#    when_code = when_code + " in facts):\n    if_when =  True"
#    
#    #condition part complete for the code.
#    when_code = when_code.replace("  ", " ")
#
#    #print when_code
#    
#    exec when_code
#    return if_when


#question view for after jumping back to a past question. it is called only once right after the jump.
def go_back_question(request):
    question_number_int = int(question_number)
    dest_question = request.session['my_questions'][int(question_number)-1]
    
    #get the questions and their facts after the destination question(jumped to) in the question list.
    questions_after_dest = []
    question_facts = []
    after_dest = False
    for question in request.session['my_questions']:
        if(question == dest_question or after_dest):
            questions_after_dest.append(question)
            question_facts.append(str(question.fact))
            question_facts.append("not_" + str(question.fact))
            after_dest = True
    
    #any of your facts obtained after the destination question, need to be removed.
    facts = [x for x in request.session['facts'] if(x not in question_facts)]
    recommendations = []
    rule_list = Rule.objects.all()
    for rule in rule_list:
        exec turnRuleIntoCode(putRuleVarsIntoOriginalRawRule(rule))
    # this is to keep the order of the list.
    request.session['recommendations'] = [x for x in request.session['recommendations'] if(x in recommendations)] 
    request.session['facts'] = facts
    request.session['counter'] = question_number_int
    
    return render_to_response('interview/webpage.html', {'question':dest_question,
                                                           'counter':request.session['counter'],})
    


def answers(request):
    try:
        f = str(request.GET['fact'])
    except:
        f = None
    
    if not(f == None):
        #add a new fact to its facts.
        #apparently there is a bug that I need to do this way(using tmp, 2 additional lines).
        tmp = request.session['facts']
        if f not in tmp : 
            tmp.append(f)
    
        request.session['facts'] = tmp
        
        #update my questions.
        #to be fully implemented later.
        #request.session['my_questions'] = updateMyQuestions(request.session['facts'], request.session['my_questions'])
        
        #from its facts, generate recommendations
        facts = list(request.session['facts'])
        recommendations = []
        num_of_my_recs = len(request.session['recommendations'])
        rule_list = Rule.objects.all()
        for rule in rule_list:
            exec turnRuleIntoCode(putRuleVarsIntoOriginalRawRule(rule))
            
        
        #any of the new recommendations to be added to your recommendations should be added to the end of your recommendations.
        for recommendation in recommendations:
            if(recommendation not in request.session['recommendations']):
                tmp = request.session['recommendations']
                tmp.append(recommendation)
                request.session['recommendations'] = tmp
                #when there is a new rec added, resoning should be added as well.
                #go through list of rules that can trigger this rec. among this rules, the one that contains this new fact f is the rule that
                #triggered this rec. then add resoning apropriately.
                for rule in returnListOfRulesByRec(recommendation):
                    if(ruleContainsThisFact(rule, f)):
                        reasoning_to_be_added = "You got this because you answered "
                        if(not rule.fact1==None and not str(rule.fact1)=="always"):
                            my_qstn, my_ans = returnQuestionbyFact(rule.fact1, request.session['my_questions'])
                            reasoning_to_be_added += str(my_ans)+" to "+str(my_qstn)
                            if(not rule.fact2==None and not str(rule.fact2)=="always"):
                                my_qstn, my_ans = returnQuestionbyFact(rule.fact2, request.session['my_questions'])
                                reasoning_to_be_added += " and "+str(my_ans)+" to "+str(my_qstn)
                                if(not rule.fact3==None and not str(rule.fact3)=="always"):
                                    my_qstn, my_ans = returnQuestionbyFact(rule.fact3, request.session['my_questions'])
                                    reasoning_to_be_added += " and "+str(my_ans)+" to "+str(my_qstn)
                            reasoning_to_be_added += " ."
                            tmp = request.session['reasonings_to_display']
                            if(reasoning_to_be_added not in tmp):
                                tmp.append(reasoning_to_be_added)
                            request.session['reasonings_to_display'] = tmp
                
    
    #for each of your recommendations, go through explanation objects and if matches get title and full explanation
    #and add to explanations list. this list will be passed to the answers page and displayed.
    explanations = []
    if(request.session['recommendations']):
        explanation_list = Explanation.objects.all()
        for recommendation in request.session['recommendations']:
            for explanation in explanation_list :                
                if(recommendation == str(explanation.rec)):
                    explanations.append([str(explanation.human_readable_form), str(explanation.detailed_description)])
            

    #pass all answered_questions and their answers to answers.html for the diagram use.
    question_list = request.session['my_questions']
    answered_questions = []
    i = 1
    previous_question = ""
    while(i <= request.session['counter']):
        if(i > 1):
            previous_question = question_list[i-2]
        else:
            previous_question = ""
        if(str(question_list[i-1].fact) in request.session['facts']):
            answered_questions.append(["Question "+str(i), question_list[i-1], previous_question, "Yes"])
        elif("not_"+str(question_list[i-1].fact) in request.session['facts']):
            answered_questions.append(["Question "+str(i), question_list[i-1], previous_question, "No"])
        else:
            answered_questions.append(["Question "+str(i), question_list[i-1], previous_question, "N/A"])
        i += 1
    return render_to_response('interview/answers.html', {'explanations':explanations,
                                                         'answered_questions':answered_questions,
                                                         'user':request.user,
                                                         'debug_info':request.session['facts'],
                                                         'reasonings_to_display':request.session['reasonings_to_display'],
                                                         'debug_info3':request.session['facts']},
                                                         context_instance=RequestContext(request))

##########################################################################
##########################################################################
##########################################################################
##########################################################################
def genPage(request):

    
    #when users login, they should get list of questions sets in their session.
    #if they don't have list, let them try a few questions as an anonymous user.
    
    if not('counter' in request.session):
        request.session['counter'] = 1
        request.session['facts'] = ['always']
        request.session['recommendations'] = []
        request.session['reasonings_to_display'] = ["You always get this."]
        
        #currently only for a test.
        question_set_list = QuestionSetList.objects.get(pk=1)
        request.session['my_questions'] = buildListOfAllQuestions(question_set_list)
        #not used yet
#        #request.session['my_questions'] = updateMyQuestions(request.session['facts'], buildListOfAllQuestions(question_set_list))
        
        
        
#    elif(request.session['counter'] > 4 and request.user.is_anonymous()):
#        return render_to_response('registration/login.html', {},
#                                  context_instance=RequestContext(request))
    #only for now for debugging.
    elif(request.session['counter'] > len(request.session['my_questions'])):
        request.session['counter'] = 1
        request.session['facts'] = ['always']
        request.session['recommendations'] = []
        request.session['reasonings_to_display'] = ["You always get this."]
        
        #currently for only a test.
        question_set_list = QuestionSetList.objects.get(pk=1)
        request.session['my_questions'] = buildListOfAllQuestions(question_set_list)
        
        #not used yet
#        request.session['my_questions'] = updateMyQuestions(request.session['facts'], buildListOfAllQuestions(question_set_list))
        
    else:
        request.session['counter'] += 1

###############################################################################################
#        Simple Array out of bounds check, just to work on website easier, rob
###############################################################################################    
    if(not request.session['counter'] > len(request.session['my_questions'])) : 
        
        ######## modified by Hideo for feature 5. ###########
        q = request.session['my_questions'][request.session['counter']-1]
        skip_counter = 0
        while(str(q.fact) in request.session['facts'] or "not_"+str(q.fact) in request.session['facts']):
            skip_counter += 1
            request.session['counter'] += 1
            if(request.session['counter'] >= len(request.session['my_questions'])):
                if(request.session['counter'] > len(request.session['my_questions'])):
                    request.session['counter'] -= 1
                break
            q = request.session['my_questions'][request.session['counter']-1]
        
        if(skip_counter == 1):
            return genPage(request)

    try:
        f = str(request.GET['fact'])
    except:
        f = ""
    
    #add a new fact to its facts.
    #apparently there is a bug that I need to do this way(using tmp, 2 additional lines).
    tmp = request.session['facts']
    if f not in tmp and f != "": 
        tmp.append(f)

    request.session['facts'] = tmp
    
    #update my questions.
    #to be fully implemented later.
    #request.session['my_questions'] = updateMyQuestions(request.session['facts'], request.session['my_questions'])
    
    #from its facts, generate recommendations
    facts = list(request.session['facts'])
    recommendations = []
    num_of_my_recs = len(request.session['recommendations'])
    rule_list = Rule.objects.all()
    for rule in rule_list:
        exec turnRuleIntoCode(putRuleVarsIntoOriginalRawRule(rule))
        
    
    #any of the new recommendations to be added to your recommendations should be added to the end of your recommendations.
    for recommendation in recommendations:
        if(recommendation not in request.session['recommendations']):
            tmp = request.session['recommendations']
            tmp.append(recommendation)
            request.session['recommendations'] = tmp
            #when there is a new rec added, reasoning should be added as well.
            #go through list of rules that can trigger this rec. among this rules, the one that contains this new fact f is the rule that
            #triggered this rec. then add resoning apropriately.
            for rule in returnListOfRulesByRec(recommendation):
                if(ruleContainsThisFact(rule, f)):
                    reasoning_to_be_added = "You got this because you answered "
                    if(not rule.fact1==None and not str(rule.fact1)=="always"):
                        my_qstn, my_ans = returnQuestionbyFact(rule.fact1, request.session['my_questions'])
                        reasoning_to_be_added += str(my_ans)+" to "+str(my_qstn)
                        if(not rule.fact2==None and not str(rule.fact2)=="always"):
                            my_qstn, my_ans = returnQuestionbyFact(rule.fact2, request.session['my_questions'])
                            reasoning_to_be_added += " and "+str(my_ans)+" to "+str(my_qstn)
                            if(not rule.fact3==None and not str(rule.fact3)=="always"):
                                my_qstn, my_ans = returnQuestionbyFact(rule.fact3, request.session['my_questions'])
                                reasoning_to_be_added += " and "+str(my_ans)+" to "+str(my_qstn)
                        reasoning_to_be_added += "."
                        tmp = request.session['reasonings_to_display']
                        tmp.append(reasoning_to_be_added)
                        request.session['reasonings_to_display'] = tmp
                
    
    #for each of your recommendations, go through explanation objects and if matches get title and full explanation
    #and add to explanations list. this list will be passed to the answers page and displayed.
    explanations = []
    if(request.session['recommendations']):
        explanation_list = Explanation.objects.all()
        for recommendation in request.session['recommendations']:
            for explanation in explanation_list :                
                if(recommendation == str(explanation.rec)):
                    explanations.append([str(explanation.human_readable_form), str(explanation.detailed_description)])
            

    #pass all answered_questions and their answers to answers.html for the diagram use.
    question_list = request.session['my_questions']
    answered_questions = []
    i = 1
    previous_question = ""
    while(i <= request.session['counter'] and i <= len(question_list)):
        if(i > 1):
            previous_question = question_list[i-2]
        else:
            previous_question = ""
        if(str(question_list[i-1].fact) in request.session['facts']):
            answered_questions.append(["Question "+str(i), question_list[i-1], previous_question, "Yes"])
        elif("not_"+str(question_list[i-1].fact) in request.session['facts']):
            answered_questions.append(["Question "+str(i), question_list[i-1], previous_question, "No"])
        else:
            answered_questions.append(["Question "+str(i), question_list[i-1], previous_question, "N/A"])
        i += 1

    if(request.session['counter'] > len(request.session['my_questions'])) :
		return render_to_response('interview/webpage.html', {'question':"",                                                           															 'counter':request.session['counter'],
                                                         #'debug_info':request.session['my_questions'],
                                                         'user':request.user,
							'num_Q' : len(request.session['my_questions']),					 								'explanations':explanations,
                                                         'answered_questions':answered_questions,
                                                         'user':request.user,
                                                         'debug_info':request.session['facts'],
                                                         'reasonings_to_display':request.session['reasonings_to_display'],
                                                         'debug_info3':request.session['facts']},
                                                           context_instance=RequestContext(request))
    else:   
        return render_to_response('interview/webpage.html', {'question':q,
                                                           'counter':request.session['counter'],
                                                           #'debug_info':request.session['my_questions'],
                                                           'user':request.user,
							'num_Q' : len(request.session['my_questions']),
														 'explanations':explanations,
                                                         'answered_questions':answered_questions,
                                                         'user':request.user,
                                                         'debug_info':request.session['facts'],
                                                         'reasonings_to_display':request.session['reasonings_to_display'],
                                                         'debug_info3':request.session['facts']},
                                                           context_instance=RequestContext(request))



##########################################################################
##########################################################################
##########################################################################
##########################################################################
def returnListOfRulesByRec(recommendation):
    result_rules = []
    rule_list = Rule.objects.all()
    for rule in rule_list:
        if(ruleContainsThisRec(rule, recommendation)):
            result_rules.append(rule)
    return result_rules

def ruleContainsThisRec(rule, recommendation):
    if(str(rule.rec1)==str(recommendation)):
        return True
    if(str(rule.rec2)==str(recommendation)):
        return True
    return False

def ruleContainsThisFact(rule, fact):
    if(str(rule.fact1)==str(fact)):
        return True
    if(str(rule.fact2)==str(fact)):
        return True
    if(str(rule.fact3)==str(fact)):
        return True
    return False

def returnQuestionbyFact(fact, this_questions):
    for question in this_questions:
        if (str(question.fact) == str(fact)):
            return question, "Yes"
        elif("not_"+str(question.fact) == str(fact)):
            return question, "No"
        
#    return "", ""

#this is a function to put variables of Rule into one Original raw rule.
#this is required to make use of the below function, turnRuleIntoCode().
def putRuleVarsIntoOriginalRawRule(rule):
    rule_condition = 'if "' + str(rule.fact1) + '"'
    if not(rule.fact2 == None):
        rule_condition = rule_condition + " " + str(rule.logical_operator1) + ' "' + str(rule.fact2) + '"'
        if not(rule.fact3 == None):
            rule_condition = rule_condition + " " + str(rule.logical_operator2) + ' "' + str(rule.fact3) + '"'
    
    rule_recs = '"' + str(rule.rec1) + '"'
    if not(rule.rec2 == None):
        rule_recs = rule_recs + ', "' + str(rule.rec2) + '"'
    
    result_raw_rule = rule_condition + " : " + rule_recs
    
    return result_raw_rule

#parses raw rule and generate python excutable code.
def turnRuleIntoCode(raw):
    
    #clean up extra spaces.
    while(raw.find("  ") >= 0):
        raw = raw.replace("  ", " ")

    condition = raw.split(":")[0]
    new_facts = raw.split(":")[1]
    code = ""
    
    #add "in facts" before all ands or ors.
    condition = condition.replace(" and ", " in facts and ")
    condition = condition.replace(" or ", " in facts or ")
        
    #add "in facts" after the last fact.
    condition = condition + " in facts:"
    
    #condition part complete for the code.
    code = condition.replace("  ", " ")
    
    #new_facts part done for the code.
    number_of_new_facts = new_facts.count(",") + 1
    i = 0
    while(i < number_of_new_facts):
        code += '\n    recommendations.append("' + new_facts.split(",")[i].replace(" ", "").replace("'", "").replace('"', '') + '")'
        i += 1
    #print code
    return code
    
    
    
    
    
    
